using System;
using System.Collections.Generic;
using System.Text;

namespace Enyo
{
	public class DataDecorator<T> : DataDecorator, IDataProcessor<T>
	{
		private DataReflector<T> m_Reflector;
		private DataRenderer<T> m_Renderer;
		private DataAllocator<T> m_Allocator;

		public virtual DataRenderer<T> Renderer
		{
			get
			{
				if (m_Renderer == null)
					m_Renderer = this.GetDefaultDecorator<DataRenderer<T>>();
				return m_Renderer;
			}
			set { m_Renderer = value; }
		}

		public virtual DataReflector<T> Reflector
		{
			get
			{
				if (m_Reflector == null)
					m_Reflector = this.GetDefaultDecorator<DataReflector<T>>();
				return m_Reflector;
			}
			set { m_Reflector = value; }
		}

		public virtual DataAllocator<T> Allocator
		{
			get
			{
				if (m_Allocator == null)
					m_Allocator = this.GetDefaultDecorator<DataAllocator<T>>();
				return m_Allocator;
			}
			set { m_Allocator = value; }
		}

		protected D GetDefaultDecorator<D>()
			where D : DataProcessor, IDataProcessor<T>
		{
			D value = null;
			try
			{
				Type[] deri = Enyo.Reflection.Type<D>.GetDerived();

				for (int i = deri.Length - 1; i >= 0; i--)
				// iterate back to front to get most specialized types first...
				{
					try
					{
						value = Enyo.Reflection.Type<D>.CreateInstance(deri[i], typeof(T));
						//value = Activator.CreateInstance(deri[i]) as D;
					}
					catch (Exception exc)
					{
						System.Diagnostics.Debug.WriteLine(exc);
						continue;
					}
					if (value != null)
						break;
				}
			}
			catch (Exception exc)
			{
				System.Diagnostics.Debug.WriteLine(exc);
				Console.WriteLine(exc);
				throw;
			}
			return value;
		}

		public virtual Enyo.Reflection.Type<T> DataType
		{
			get { return new Enyo.Reflection.Type<T>(); }
		}

		public virtual T Process(T value)
		{
			return value;
		}

		#region IDataProcessor<T> Members


		#endregion

		protected override DataRenderer _Renderer
		{
			get
			{
				return this.Renderer;
			}
			set
			{
				this.Renderer = (DataRenderer<T>)value;
			}
		}

		protected override DataReflector _Reflector
		{
			get
			{
				return this.Reflector;
			}
			set
			{
				this.Reflector = (DataReflector<T>)value;
			}
		}

		protected override DataAllocator _Allocator
		{
			get
			{
				return this.Allocator;
			}
			set
			{
				this.Allocator = (DataAllocator<T>)value;
			}
		}

		public Enyo.DataInformation<T> Information
		{
			get { return (this.Reflector != null ? this.Reflector.Information : null); }
			set { if (this.Reflector != null) this.Reflector.Information = value; }
		}
	}
}
